`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/05 23:16:46
// Design Name: 
// Module Name: axi_slave
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_slave(
input logic ACLK,
input logic ARESETn,
//AR
input logic ARVALID,
input logic [31:0] ARADDR,
input logic [7:0] ARLEN,
output logic ARREADY,
//R
output logic [31:0] RDATA,
output logic RVALID,
output logic RLAST,
output logic [1:0] RRESP,
input logic RREADY,
//AW
input logic AWVALID,
input logic [31:0] AWADDR,
input logic [7:0] AWLEN,
input logic [2:0] AWSIZE,
input logic [1:0] AWBURST,
output logic AWREADY,
//W
input logic [31:0] WDATA,
input logic WVALID,
input logic WLAST,
input logic [3:0] WSTRB,
output logic WREADY,
//B
output logic BVALID,
output logic [1:0] BRESP,
input logic BREADY
    );
parameter N=128;
parameter IDLE=0;
parameter BUSY=1;
logic state,next_state;                     //处理读请求的状态机
logic state_w,next_state_w;                 //处理写请求的状态机
//读请求FIFO相关信号
logic empty;
logic full;
logic rd_en;
logic wr_en;
logic [63:0] rdata;
logic [63:0] wdata;
logic [63:0] RAM [0:N-1];
logic [31:0] rd_cnt;                        //读数据计数器
logic [31:0] rd_len;                        //本次请求的读数据个数
logic [31:0] rd_addr;                       //本次请求的读起始地址
//写请求FIFO相关信号
logic empty_aw;
logic full_aw;
logic rd_en_aw;
logic wr_en_aw;
logic [63:0] wdata_aw;                  //len+addr
logic [63:0] rdata_aw;
logic [31:0] wr_cnt;                    //已经写入的数据的个数
logic [31:0] aw_len;                    //写突发长度-1
logic [31:0] aw_addr;                   //写突发起始地址
//写数据FIFO相关信号
logic empty_w;
logic full_w;
logic rd_en_w;
logic wr_en_w;
logic [31:0] rdata_w;
logic [31:0] wdata_w;
logic data_valid;                       //从写数据FIFO中读出数据的有效信号
logic [31:0] data_cnt;
//RAM初始化
initial
begin
   for(int i=0;i<N;i++)
       RAM[i]=i;
end
//wdata,rdata
assign wdata={24'd0,ARLEN,ARADDR};
assign {rd_len,rd_addr}=rdata;
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    ARREADY<=0;
else if(ARVALID&&~ARREADY&&~full)                //FIFO未满方可接收新的请求
    ARREADY<=1;
else if(ARVALID&&ARREADY)
    ARREADY<=0;
//wr_en
assign wr_en=(ARVALID&&ARREADY)?1'b1:1'b0;
//state
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    state<=IDLE;
else 
    state<=next_state;
//
always_comb
begin
    case(state)
	    IDLE:if(~empty)                //若非空,则进入busy状态开始下一次传输
		         next_state=BUSY;
			 else
			     next_state=IDLE;
		BUSY:if(RVALID&&RLAST&&RREADY)
		         next_state=IDLE;
			 else 
			     next_state=BUSY;
		default:next_state=IDLE;
	endcase
end
//RDATA
always_comb
begin
    RDATA=RAM[rd_addr+rd_cnt];
end
//RLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    RLAST<=0;
else if(rd_cnt==rd_len-1&&RVALID&&RREADY)                 //倒数第二个数据完成
    RLAST<=1;
else if(RVALID&&RREADY&&RLAST)
    RLAST<=0;
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    RVALID<=0;
else if(rd_en)
    RVALID<=1;
else if(RVALID&&RREADY&&RLAST)
    RVALID<=0;
//RRESP
assign RRESP=2'b00;
//rd_en
always_comb
begin
    if(state==IDLE)
	     if(~empty)
		     rd_en=1;
		 else
		     rd_en=0;
	else
	     rd_en=0;
end
//rd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
   rd_cnt<=0;
else if(rd_en)
   rd_cnt<=0;
else if(RVALID&&RREADY)
   rd_cnt<=rd_cnt+1;
//**********************************************************处理写请求的逻辑*****************************************************************
//状态转化
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    state_w<=IDLE;
else
    state_w<=next_state_w;
//状态转移判断
always_comb
begin
    case(state_w)
	    IDLE:if(~empty_aw)                         //写请求命令FIFO非空
		         next_state_w=BUSY;
			 else
			     next_state_w=IDLE;
		BUSY:if(BVALID&&BREADY)                    //一次写请求的数据已经全部处理完成                 
		         next_state_w=IDLE;
		default:next_state_w=IDLE;
	endcase
end
//写命令FIFO,wdata_aw,rdata_aw
assign wdata_aw={24'd0,AWLEN,AWADDR};
assign {aw_len,aw_addr}=rdata_aw;
//写数据FIFO,wdata_w,rdata_w
assign wdata_w=WDATA;
//wr_en_aw,写命令FIFO的写使能信号
always_comb
if(AWREADY&&AWVALID&&~full_aw)                      //写地址握手完成,并且写命令fifo非满
    wr_en_aw=1;
else
    wr_en_aw=0;
//rd_en_aw，写命令FIFO的读使能信号
always_comb
begin
   if(state_w==IDLE&&~empty_aw)                   //当前处于IDLE状态且AW FIFO非空时,拉高rd_en_aw,读取下一条待处理写请求
       rd_en_aw=1;
   else
       rd_en_aw=0;
end
//rd_en_w，写数据FIFO的读使能信号
always_comb
if(state_w==BUSY&&~empty_w&&wr_cnt<=aw_len)                 //正在处理写请求,且写数据FIFO非空,写数据还未完成时，拉高rd_en_w
    rd_en_w=1;
else
    rd_en_w=0;
//wr_en_w,写数据FIFO的写使能信号
always_comb
if(WREADY&&WVALID&&~full_w)
   wr_en_w=1;
else
   wr_en_w=0;
//wr_cnt，写数据计数器
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    wr_cnt<=0;
else if(rd_en_aw)                   //从写命令FIFO读出一个写请求时,清零wr_cnt
    wr_cnt<=0;
else if(rd_en_w)                    //每次从写数据FIFO读出一个数据,wr_cnt+1
    wr_cnt<=wr_cnt+1;
//data_valid,写数据FIFO读出数据有效信号
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
   data_valid<=0;
else
   data_valid<=rd_en_w;
//data_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
   data_cnt<=0;
else
   data_cnt<=wr_cnt;
//写数据到RAM中
always_ff@(posedge ACLK)
if(data_valid)
begin
    RAM[aw_addr+data_cnt]<=rdata_w;
	$display("write %d into address %d",rdata_w,aw_addr+data_cnt);
end
//WREADY
always_comb
begin
   if(~full_w&&WVALID)        //数据有效且FIFO未满，则接收数据
       WREADY=1;
   else
       WREADY=0;
end
//AWREADY
always_comb
if(~full_aw&&AWVALID)          //命令有效且写命令FIFO未满,则接收命令
    AWREADY=1;
else
    AWREADY=0;
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    BVALID<=0;
else if(state_w==BUSY&&wr_cnt==aw_len&&rd_en_w==1'b1)                  //本次写传输最后一个数据传输完成
    BVALID<=1;
else if(BVALID&&BREADY)
    BVALID<=0;
//BRESP
assign BRESP=2'b00;
//********************************************************************************************************************************************
//read outstanding cmd fifo
sync_fifo
#(.DATA_WIDTH(64),
  .FIFO_DEPTH(8))
U
(
.clk(ACLK),
.rst(~ARESETn),
.wr_en(wr_en),
.wdata(wdata),
.rd_en(rd_en),
.rdata(rdata),
.full(full),
.empty(empty)
);
//write outstanding cmd fifo
sync_fifo
#(.DATA_WIDTH(64),
  .FIFO_DEPTH(4))
U_AW
(
.clk(ACLK),
.rst(~ARESETn),
.wr_en(wr_en_aw),
.wdata(wdata_aw),
.rd_en(rd_en_aw),
.rdata(rdata_aw),
.full(full_aw),
.empty(empty_aw)
);
//write outstanding data fifo
sync_fifo
#(.DATA_WIDTH(32),
  .FIFO_DEPTH(4*256))
U_W
(
.clk(ACLK),
.rst(~ARESETn),
.wr_en(wr_en_w),
.wdata(wdata_w),
.rd_en(rd_en_w),
.rdata(rdata_w),
.full(full_w),
.empty(empty_w)
);
endmodule
